﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using WJP.Logging;
using WJP.Queue.Socketing.BufferManagement;
using WJP.Utils;

namespace WJP.Queue.Socketing
{
    /// <summary>
    /// Socket服务
    /// </summary>
    public class ServerSocket
    {
        #region 属性、字段

        private readonly Socket _socket;
        private readonly SocketSetting _setting;
        private readonly IPEndPoint _listeningEndPoint;
        private readonly SocketAsyncEventArgs _acceptSocketArgs;
        private readonly IList<IConnectionEventListener> _connectionEventListeners;
        private readonly Action<ITcpConnection, byte[], Action<byte[]>> _messageArrivedHandler;
        private readonly IBufferPool _receiveDataBufferPool;
        private readonly ConcurrentDictionary<Guid, ITcpConnection> _connectionDict;
        private readonly ILogger _logger;
        private readonly string _name;

        #endregion

        #region 构造函数

        public ServerSocket(string name, IPEndPoint listeningEndPoint, SocketSetting setting, IBufferPool receiveDataBufferPool, Action<ITcpConnection, byte[], Action<byte[]>> messageArrivedHandler)
        {
            Ensure.NotNull(listeningEndPoint, "listeningEndPoint");
            Ensure.NotNull(setting, "setting");
            Ensure.NotNull(receiveDataBufferPool, "receiveDataBufferPool");
            Ensure.NotNull(messageArrivedHandler, "messageArrivedHandler");

            _name = name;
            _listeningEndPoint = listeningEndPoint;
            _setting = setting;
            _receiveDataBufferPool = receiveDataBufferPool;
            _connectionEventListeners = new List<IConnectionEventListener>();
            _messageArrivedHandler = messageArrivedHandler;
            _connectionDict = new ConcurrentDictionary<Guid, ITcpConnection>();
            _socket = SocketUtils.CreateSocket(_setting.SendBufferSize, _setting.ReceiveBufferSize);
            _acceptSocketArgs = new SocketAsyncEventArgs();
            _acceptSocketArgs.Completed += AcceptCompleted;
            _logger = LogManager.Logger;
        }

        #endregion

        /// <summary>
        /// 注册监听Socket的连接事件
        /// </summary>
        /// <param name="listener"></param>
        public void RegisterConnectionEventListener(IConnectionEventListener listener)
        {
            _connectionEventListeners.Add(listener);
        }

        /// <summary>
        /// 启动Socket服务，默认挂起的连接队列的最大长度为5000
        /// </summary>
        public void Start()
        {
            _logger.InfoFormat("Socket服务启动中，名称：{0}，监听终结点：{1}", _name, _listeningEndPoint);

            try
            {
                _socket.Bind(_listeningEndPoint);
                _socket.Listen(5000);
            }
            catch (Exception ex)
            {
                _logger.Error("Socket服务启动失败，名称：{0}，监听终结点：{1}".FormatArgs(_name, _listeningEndPoint), ex);
                SocketUtils.ShutdownSocket(_socket);
                throw;
            }

            StartAccepting();
        }

        /// <summary>
        /// 关闭Socket服务
        /// </summary>
        public void Shutdown()
        {
            SocketUtils.ShutdownSocket(_socket);
            _logger.InfoFormat("Socket服务已关闭，名称：{0}，监听终结点：{1}", _name, _listeningEndPoint);
        }

        /// <summary>
        /// 开始一个异步操作以接受传入的连接尝试
        /// </summary>
        private void StartAccepting()
        {
            try
            {
                var firedAsync = _socket.AcceptAsync(_acceptSocketArgs);
                if (!firedAsync)
                    ProcessAccept(_acceptSocketArgs);
            }
            catch (Exception ex)
            {
                if(!(ex is ObjectDisposedException))
                {
                    _logger.Error("Socket服务发生异常，名称：{0}，监听终结点：{1}".FormatArgs(_name, _listeningEndPoint), ex);
                }
                Task.Factory.StartNew(() => StartAccepting());
            }
        }

        /// <summary>
        /// 连接完成
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void AcceptCompleted(object sender, SocketAsyncEventArgs e)
        {
            ProcessAccept(e);
        }

        /// <summary>
        /// 接入一个连接
        /// </summary>
        /// <param name="e"></param>
        private void ProcessAccept(SocketAsyncEventArgs e)
        {
            try
            {
                if(e.SocketError == SocketError.Success)
                {
                    var acceptSocket = e.AcceptSocket;
                    e.AcceptSocket = null;
                    OnSocketAccepted(acceptSocket, e.UserToken);
                }
                else
                {
                    SocketUtils.ShutdownSocket(e.AcceptSocket);
                    e.AcceptSocket = null;
                }
            }
            catch (Exception ex)
            {
                if(!(ex is ObjectDisposedException))
                {
                    _logger.Error("Socket服务发生异常，名称：{0}，监听终结点：{1}".FormatArgs(_name, _listeningEndPoint), ex);
                }
            }
            finally
            {
                StartAccepting();
            }
        }

        /// <summary>
        /// Socket连接完成
        /// </summary>
        /// <param name="socket"></param>
        /// <param name="userToken"></param>
        private void OnSocketAccepted(Socket socket, object userToken)
        {
            Task.Factory.StartNew(() =>
            {
                try
                {
                    //var connection = new TcpConnection(_name, socket, _setting, _receiveDataBufferPool, OnMessageArrived, OnConnectionClosed);
                }
                catch (Exception)
                {

                    throw;
                }
            });
        }
    }
}
